package pCloud.stream;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import pCloud.PCloudAttributeAndType;

/*
 * Simple Expression Class:
 * A simple expression is of form x op v,
 * where x is a vairalbe, op is a operator taken from set {>,<,=,<>,>=,<=}, 
 * and v is a number or string value
 * 
 */

public class SimpleExpression {
	String variable = "";
	String operator = "";
	String value = "";
	
	
	// checking if String s represents a float number
	
	public boolean isFloat(String s) {
		
		try {
			
		    Float.parseFloat(s);
			return true;
		}
		catch (NumberFormatException nx){
			
			return false;
		}
	}
	
	public float getFloat(String s){
		
		float f = 0;
		try {
    		
    			f = Float.parseFloat(s);
    			     	
		}
    	
		catch (NumberFormatException nx){
    		
			System.out.println("Error converting to float number : " + s ); 	
			System.exit(0);
		}
		
		return f;
	}
	
	public void print() {
		
		System.out.println("variable is " + this.variable);
		System.out.println("operator is " + this.operator);
		System.out.println("value is " + this.value);
	}
	
	public SimpleExpression(String var, String op, String val){
		this.variable = var;
		this.operator = op;
		this.value = val;
		
	}
	
    public SimpleExpression(String s){
		
		//construct an object by parsing the input simple expression in string format
	
		//Matching Order >=, <=, <>, >, <, =
    	
    		//Known Problem: Will have problem matching =>, =<, >< !!!!
		
		String[] patterns = {">=","<=","<>",">","<","="};
		Pattern pattern;
		Matcher matcher;
		boolean found = false;
		
		s=s.replaceAll("\\s+", ""); // remove all white spaces.
		
		for(int i=0;i<patterns.length;i++){
			
			pattern=Pattern.compile(patterns[i]);
			matcher = pattern.matcher(s);
			
			if(matcher.find()){
				
				this.operator = matcher.group();
				this.variable = s.substring(0, matcher.start());
				this.value = s.substring(matcher.end());
				found = true;
				break;
			}
		}
		
		if (!found) {
						
			System.out.println("invalid expression !!");
			System.exit(0);
		}
	}
    
    public String toString(){
    	
    		return this.variable + this.operator + this.value;
    }
    
    
    //This operator is >=
    public String mergeGEAnd(SimpleExpression se) {

    		String result = "";
    		
    		if (se.operator.equals(">=")) {
				
    			float f1 = getFloat(this.value);
    			float f2 = getFloat(se.value);
    			
			if (f1 < f2) {
					
				result = se.toString();
			}
			
			else if (f1==f2){
				
				result = this.toString();
			}
			else {
				result = this.toString();
					
			}				
				
		}
		else if (se.operator.equals("<=")){
					 	
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
				
			if (f1 < f2) {
				result = this.toString() + " && " + se.toString();
			}
			else if (f1==f2){
					
				result = this.variable + "=" + this.value;
					
			}
			else {
					
				result = PCloudAttributeAndType.NO_RESULT_WARNING ;
			}
		
		}
		
		else if (se.operator.equals(">")){
			
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
				
			if (f1 < f2 ){
					
				result = this.variable + ">" + se.value;
					
			}
			else if (f1 == f2){
				result = se.toString();
			}
			else {
				result = this.toString();
					
			}
		
		}    		
		else if (se.operator.equals("<")){
				
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
					result = this.toString() + " && " + se.toString();
			}
			else if (f1==f2){
				
				result = PCloudAttributeAndType.NO_RESULT_WARNING ;
				
			}
			else {
				
				result = PCloudAttributeAndType.NO_RESULT_WARNING ;
			}							
		}
    		
		else if (se.operator.equals("=")){
			
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				result = se.toString();
			}
			else if (f1==f2){
			
				result = se.toString() ;
			
			}
			else {
			
				result = PCloudAttributeAndType.NO_RESULT_WARNING ;
			}						
				
		}
    		
		else if (se.operator.equals("<>")){

			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				result = this.toString() + " && " + se.toString();
			}
			else if (f1==f2){
			
				result = this.variable + ">" + this.value;
			
			}
			else {
			
				result = this.toString();
			}			
			
		}
		else {

			System.out.println("Invalid Operator : " + se.operator + "!!!");
    			System.exit(0);
			
		}
    		
    		
    		return result;
	
    }
    
    
    //This operator is <=
    public String mergeLEAnd(SimpleExpression se) {

    		String result = "";
    		
		if (se.operator.equals(">=")) {
				
    			float f1 = getFloat(this.value);
    			float f2 = getFloat(se.value);
    			
			if (f1 < f2) {
					
				result = PCloudAttributeAndType.NO_RESULT_WARNING ;
			}
			else if (f1 == f2){
				
				result = this.variable + "=" + this.value;
			}
			else {
				result = this.toString() + " && " + se.toString();
					
			}				
				
		}
		else if (se.operator.equals("<=")){
					 	
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
				
			if (f1 < f2) {
				result = this.toString();
			}
			else if (f1==f2){
					
				result = this.toString();
					
			}
			else {
					
				result = se.toString() ;
			}
		
		}
		
		else if (se.operator.equals(">")){
			
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
				
			if (f1 < f2 ){
					
				result = PCloudAttributeAndType.NO_RESULT_WARNING;
					
			}
			else if (f1 == f2){
				result = PCloudAttributeAndType.NO_RESULT_WARNING;
			}
			else {
				result = this.toString() + " && " + se.toString();
					
			}
		
		}    		
		else if (se.operator.equals("<")){
				
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				 result = this.toString();
			}
			else if (f1==f2){
				
				result = se.toString() ;
				
			}
			else {
				
				result = se.toString();
			}							
		}
    		
		else if (se.operator.equals("=")){
			
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				result = PCloudAttributeAndType.NO_RESULT_WARNING ;;
			}
			else if (f1==f2){
			
				result = se.toString() ;
			
			}
			else {
			
				result = se.toString() ;
			}									
		}
    		
		else if (se.operator.equals("<>")){

			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				result = this.toString();
			}
			else if (f1==f2){
			
				result = this.variable + "<" + this.value;
			
			}
			else {
			
				result = this.toString() + " && " + se.toString();
			}			
			
		}
		else {

			System.out.println("Invalid Operator : " + se.operator + "!!!");
    			System.exit(0);
			
		}
    		  		
    		return result;
	
    }
    
    //This operator is >
    public String mergeGTAnd(SimpleExpression se) {

    		String result = "";
    		
    		if (se.operator.equals(">=")) {
				
    			float f1 = getFloat(this.value);
    			float f2 = getFloat(se.value);
    			
			if (f1 < f2) {
					
				result = se.toString() ;
			}
			else if (f1 == f2){
				
				result = this.toString();
			}
			else {
				result = this.toString();
					
			}				
				
		}
		else if (se.operator.equals("<=")){
					 	
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
				
			if (f1 < f2) {
				result = this.toString() + " && " + se.toString();
			}
			else if (f1==f2){
					
				result = PCloudAttributeAndType.NO_RESULT_WARNING;
					
			}
			else {
					
				result = PCloudAttributeAndType.NO_RESULT_WARNING;
			}
		
		}
		
		else if (se.operator.equals(">")){
			
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
				
			if (f1 < f2 ){
					
				result = se.toString();
					
			}
			else if (f1 == f2){
				result = se.toString();
			}
			else {
				result = this.toString();
					
			}
		
		}    		
		else if (se.operator.equals("<")){
				
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				 result = this.toString() + " && " + se.toString();
			}
			else if (f1==f2){
				
				result = PCloudAttributeAndType.NO_RESULT_WARNING ;
				
			}
			else {
				
				result = PCloudAttributeAndType.NO_RESULT_WARNING;
			}							
		}
    		
		else if (se.operator.equals("=")){
			
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				result = se.toString();
			}
			else if (f1==f2){
			
				result = PCloudAttributeAndType.NO_RESULT_WARNING;
			
			}
			else {
			
				result =  PCloudAttributeAndType.NO_RESULT_WARNING;
			}									
		}
    		
		else if (se.operator.equals("<>")){

			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				result = this.toString() + " && " + se.toString();
			}
			else if (f1==f2){
			
				result = this.toString();
			
			}
			else {
			
				result = this.toString();
			}			
			
		}
		else {

			System.out.println("Invalid Operator : " + se.operator + "!!!");
    			System.exit(0);
			
		}
    		
    		return result;
	
    }
    
    //This operator is <
    public String mergeLTAnd(SimpleExpression se) {

    		String result = "";
    		
    		if (se.operator.equals(">=")) {
				
    			float f1 = getFloat(this.value);
    			float f2 = getFloat(se.value);
    			
			if (f1 < f2) {
					
				result = PCloudAttributeAndType.NO_RESULT_WARNING ;
			}
			else if (f1 == f2){
				
				result = PCloudAttributeAndType.NO_RESULT_WARNING ;
			}
			else {
				result = this.toString() + " && " + se.toString();
					
			}				
				
		}
		else if (se.operator.equals("<=")){
					 	
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
				
			if (f1 < f2) {
				result = this.toString();
			}
			else if (f1==f2){
					
				result = this.toString();
					
			}
			else {
					
				result = se.toString() ;
			}
		
		}
		
		else if (se.operator.equals(">")){
			
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
				
			if (f1 < f2 ){
					
				result = PCloudAttributeAndType.NO_RESULT_WARNING;
					
			}
			else if (f1 == f2){
				result = PCloudAttributeAndType.NO_RESULT_WARNING;
			}
			else {
				result = this.toString() + " && " + se.toString();
					
			}
		
		}    		
		else if (se.operator.equals("<")){
				
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				 result = this.toString();
			}
			else if (f1==f2){
				
				result = se.toString() ;
				
			}
			else {
				
				result = se.toString();
			}							
		}
    		
		else if (se.operator.equals("=")){
			
			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				result = PCloudAttributeAndType.NO_RESULT_WARNING ;;
			}
			else if (f1==f2){
			
				result = se.toString() ;
			
			}
			else {
			
				result = se.toString() ;
			}									
		}
    		
		else if (se.operator.equals("<>")){

			float f1 = getFloat(this.value);
			float f2 = getFloat(se.value);
			
			if (f1 < f2) {
				result = this.toString();
			}
			else if (f1==f2){
			
				result = this.toString();
			
			}
			else {
			
				result = this.toString() + " && " + se.toString();
			}			
			
		}
		else {

			System.out.println("Invalid Operator : " + se.operator + "!!!");
    			System.exit(0);
			
		}
   		
    		return result;
	
    }
    
    //This operator is =
    public String mergeEQAnd(SimpleExpression se) {

    		String result = "";
    		
    		if (!isFloat(this.value)) {
    		
    			// value of this expression is a string (not a number), 
    			// the operator of the merging expression should only be "=" && "<>"
    			// the value of the merging expression should be string only. 
    			   			
    			if ((se.operator.equals("=") || se.operator.equals("<>")) && !isFloat(se.value)){
    				
    				if (se.operator.equals("=")) {
    					if (this.value.equals(se.value)){ 					
    						result = this.toString();
    					}
    					else {
    					
    						result = PCloudAttributeAndType.NO_RESULT_WARNING; 
    					}
    				}
    				else if (se.operator.equals("<>")){
    					
    					if (this.value.equals(se.value)){ 					
    						result = PCloudAttributeAndType.NO_RESULT_WARNING;
    					}
    					else {
    					
    						result = this.toString(); 
    					}
    				}
    				
    			}
    			else {
    				result = PCloudAttributeAndType.NO_RESULT_WARNING;   				
    			}
    		}
    		else {
    			
    			 			
    			if (se.operator.equals(">=")) {
    				
        			float f1 = getFloat(this.value);
        			float f2 = getFloat(se.value);
        			
    			if (f1 < f2) {
    					
    				result = PCloudAttributeAndType.NO_RESULT_WARNING ;
    			}
    			else if (f1 == f2){
    				
    				result = this.toString() ;
    			}
    			else {
    				result = this.toString();
    					
    			}				
    				
    			}
    			else if (se.operator.equals("<=")){
    					 	
    				float f1 = getFloat(this.value);
    				float f2 = getFloat(se.value);
    				
    				if (f1 < f2) {
    					result = this.toString();
    				}
    				else if (f1==f2){
    					
    					result = this.toString();
    					
    				}
    				else {
    					
    					result = PCloudAttributeAndType.NO_RESULT_WARNING ; ;
    				}
    		
    			}
    		
    			else if (se.operator.equals(">")){
    			
    				float f1 = getFloat(this.value);
    				float f2 = getFloat(se.value);
    				
    				if (f1 < f2 ){
    					
    					result = PCloudAttributeAndType.NO_RESULT_WARNING;
    					
    				}
    				else if (f1 == f2){
    					result = PCloudAttributeAndType.NO_RESULT_WARNING;
    				}
    				else {
    					result = this.toString();
    					
    				}
    		
    			}    		
    			else if (se.operator.equals("<")){
    				
    				float f1 = getFloat(this.value);
    				float f2 = getFloat(se.value);
    			
    				if (f1 < f2) {
    					result = this.toString();
    				}
    				else if (f1==f2){
    				
    					result = PCloudAttributeAndType.NO_RESULT_WARNING;
    				
    				}
    				else {
    				
    					result = PCloudAttributeAndType.NO_RESULT_WARNING;
    				}							
    			}
        		
    			else if (se.operator.equals("=")){
    			
    				float f1 = getFloat(this.value);
    				float f2 = getFloat(se.value);
    			
    				if (f1 < f2) {
    					result = PCloudAttributeAndType.NO_RESULT_WARNING ;;
    				}
    				else if (f1==f2){
    			
    					result = this.toString() ;
    			
    				}
    				else {
    			
    					result = PCloudAttributeAndType.NO_RESULT_WARNING;
    				}									
    			}
        		
    			else if (se.operator.equals("<>")){

    				float f1 = getFloat(this.value);
    				float f2 = getFloat(se.value);
    			
    				if (f1 < f2) {
    					result = this.toString();
    				}
    				else if (f1==f2){
    			
    					result = PCloudAttributeAndType.NO_RESULT_WARNING ;
    			
    				}
    				else {
    			
    					result = this.toString();
    				}			
    			
    			}
    			else {

    				System.out.println("Invalid Operator : " + se.operator + "!!!");
        			System.exit(0);
    			
    			}  			
    		}
    		return result;
	
    }
    
    //This operator is <>
    public String mergeNEAnd(SimpleExpression se) {

		String result = "";
		
		if (!isFloat(this.value)) {
		
			// value of this expression is a string (not a number), 
			// the operator of the merging expression should only be "=" && "<>"
			// the value of the merging expression will be considered as string only. 
			   			
			if ((se.operator.equals("=") || se.operator.equals("<>")) && !isFloat(se.value)){
				
				if (se.operator.equals("=")) {
					if (this.value.equals(se.value)){ 					
						result = PCloudAttributeAndType.NO_RESULT_WARNING;
					}
					else {
					
						result = se.toString(); 
					}
				}
				else if (se.operator.equals("<>")){
					
					if (this.value.equals(se.value)){ 					
						result = this.toString();
					}
					else {
					
						result = this.toString() + " && " + se.toString(); 
					}
				}
				
			}
			else {
				result = PCloudAttributeAndType.NO_RESULT_WARNING;   				
			}
		}
		else {
						 			
			if (se.operator.equals(">=")) {
				
    			float f1 = getFloat(this.value);
    			float f2 = getFloat(se.value);
    			
			if (f1 < f2) {
					
				result = se.toString();
			}
			else if (f1 == f2){
				
				result = this.variable + ">" + this.value ; ;
			}
			else {
				result = this.toString() + " && " + se.toString();
					
			}				
				
			}
			else if (se.operator.equals("<=")){
					 	
				float f1 = getFloat(this.value);
				float f2 = getFloat(se.value);
				
				if (f1 < f2) {
					result = this.toString() + " && " + se.toString();
				}
				else if (f1==f2){
					
					result = this.variable + "<" + this.value;
					
				}
				else {
					
					result = se.toString();
				}
		
			}
		
			else if (se.operator.equals(">")){
			
				float f1 = getFloat(this.value);
				float f2 = getFloat(se.value);
				
				if (f1 < f2 ){
					
					result = se.toString();
					
				}
				else if (f1 == f2){
					result = se.toString();
				}
				else {
					result = this.toString() + " && " + se.toString();
					
				}
		
			}    		
			else if (se.operator.equals("<")){
				
				float f1 = getFloat(this.value);
				float f2 = getFloat(se.value);
			
				if (f1 < f2) {
					result = this.toString() + " && " +  se.toString();
				}
				else if (f1==f2){
				
					result = se.toString();
				
				}
				else {
				
					result = se.toString();
				}							
			}
    		
			else if (se.operator.equals("=")){
			
				float f1 = getFloat(this.value);
				float f2 = getFloat(se.value);
			
				if (f1 < f2) {
					result = se.toString();
				}
				else if (f1==f2){
			
					result = PCloudAttributeAndType.NO_RESULT_WARNING ;
			
				}
				else {
			
					result = se.toString();
				}									
			}
    		
			else if (se.operator.equals("<>")){

				float f1 = getFloat(this.value);
				float f2 = getFloat(se.value);
			
				if (f1 < f2) {
					result = this.toString() + " && " + se.toString();
				}
				else if (f1==f2){
			
					result = this.toString();
			
				}
				else {
			
					result = this.toString() + " && " + se.toString();
				}			
			
			}
			else {

				System.out.println("Invalid Operator : " + se.operator + "!!!");
    			System.exit(0);
			
			}  			
		}
		return result;
	
    }
    
    
    // merge this simple expression with another with same variable name, result is a String that satisfies both. 
    public String merge(SimpleExpression se){
    	
    		String result = "";
    		
    		if(this.variable.equals(se.variable)){
    			
    			if (this.operator.equals(">=")) {
    				
    				result = this.mergeGEAnd(se);
    				
    			}
    			else if (this.operator.equals("<=")){
    				result = this.mergeLEAnd(se);
    			}
    			else if (this.operator.equals("<>")){
    				result = this.mergeNEAnd(se);
    			}
    			else if (this.operator.equals(">")){
    				result = this.mergeGTAnd(se);
    			}
    			else if (this.operator.equals("<")){
    				result = this.mergeLTAnd(se);
    			}
    			else if (this.operator.equals("=")){
    				result = this.mergeEQAnd(se);
    			}
    			else {
	
    				System.out.println("Invalid Operator : " + this.operator + "!!!");
        			System.exit(0);
    			}
    			
    		}
    		else {
    			
    			System.out.println("Error during expression merging. Variable name different.");
    			System.exit(0);
    		}
    		
    		return result;
    }
    
    
    public static void main(String[] args) {
    	
    		SimpleExpression se1 = new SimpleExpression("a <335.3");
    		SimpleExpression se2 = new SimpleExpression("a >315.23");
    		
    		System.out.println(se1.merge(se2));
    	
    }
}
